package cn.green.manage.service;

import cn.green.core.components.database.DBRouter;
import cn.green.core.components.field.FieldTypeCom;
import cn.green.core.components.store.field.FieldTypeStore;
import cn.green.core.executor.DclExecutor;
import cn.green.core.executor.DdlExecutor;
import cn.green.manage.cache.QCache;
import cn.green.manage.curd.QFieldCurd;
import cn.green.manage.curd.QTableCurd;
import cn.green.core.model.QField;
import cn.green.core.model.QTable;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * @author wang.yishu
 * @version 1.0
 * @className QDdlService
 * @description ddlService
 * @date 2025/1/16 13:46
 */
//done
@Transactional(readOnly = true)
public class QDdlService {
    protected QTableCurd qTableCurd;
    protected QFieldCurd qFieldCurd;
    protected QCache qCache;
    protected DdlExecutor ddlExecutor;
    protected DclExecutor dclExecutor;
    protected DBRouter dbRouter;

    public QDdlService(QTableCurd tableDao, QFieldCurd fieldDao, QCache cache, DdlExecutor ddlExecutor,
                       DclExecutor dclExecutor, DBRouter dbRouter) {
        this.qTableCurd = tableDao;
        this.qFieldCurd = fieldDao;
        this.qCache = cache;
        this.ddlExecutor = ddlExecutor;
        this.dclExecutor = dclExecutor;
        this.dbRouter = dbRouter;
    }
    /**
     * 列表
     * @param param 查询参数
     * @return 数据
     */
    public List<QTable> tableList(QTable param) {
        return this.qTableCurd.findTable(param);
    }

    /**
     * 获取对应表名的表结构
     * @param tableName 表名
     * @return 数据行
     */
    public QTable getTable(String source, String scheme, String tableName) {
        if (!this.qCache.tableExistsInCache(source, scheme, tableName)) {
            //不在缓存中
            QTable qTable = this.qTableCurd.selectTable(source, scheme, tableName);
            if (qTable != null) {
                this.qCache.setTableToCache(qTable);
                List<QField> fieldsByTableName = this.qFieldCurd.findFieldsByTableName(source, scheme, tableName);
                for (QField qField : fieldsByTableName) {
                    this.qCache.setFieldToCache(qField);
                }
            } else {
                return null;
            }
        }
        QTable tableFromCache = this.qCache.getTableFromCache(source, scheme, tableName);
        List<QField> fieldsFromCache = this.qCache.getFieldsFromCache(source, scheme, tableName);
        if (fieldsFromCache != null && !fieldsFromCache.isEmpty()) {
            fieldsFromCache.sort((o1, o2) -> {
                int o1Sort = o1.getSort() == null ? 0 : o1.getSort();
                int o2Sort = o2.getSort() == null ? 0 : o2.getSort();
                return o1Sort - o2Sort;
            });
        }
        tableFromCache.setFields(fieldsFromCache);
        return tableFromCache;
    }

    @Transactional(rollbackFor = Exception.class)
    public int updateTable(QTable table) {
        //todo 修改表信息暂时
        //QTable qTable = this.qTableCurd.updateTable(table);
        throw new RuntimeException("暂时无法修改表信息");
    }

    /**
     * 初始化表结构信息
     * @param table 表结构
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public int initialTable(QTable table) {
        if (dclExecutor.existTable(table)) {
            throw new RuntimeException("QTable initial table error: table names: [" +table.getTableName()+ "] has exists!");
        }
        table.setDelStatus(0);
        table.setCreateTime(new Date());
        if (table.getSchemeName() == null || table.getSchemeName().isEmpty()) {
            table.setSchemeName(dbRouter.getMaster().getSchemeName());
        }
        QTable qTable = this.qTableCurd.insertTable(table);
        if (qTable != null) {
            this.qCache.setTableToCache(table);
            List<QField> fields = table.initialFields();
            for (QField field : fields) {
                field.setDelStatus(0);
                field.setCreateTime(new Date());
                field.setTableName(qTable.getTableName());
                field.setSourceName(qTable.getSourceName());
                field.setSchemeName(qTable.getSchemeName());
                field.setTableId(qTable.getId());
                QField insertFieldInfo = this.qFieldCurd.insertFieldInfo(field);
                this.qCache.setFieldToCache(insertFieldInfo);
            }
        }
        ddlExecutor.executeCrtTable(table);
        return 1;
    }

    /**
     * 新增字段
     * @param field 字段结构
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public int addField(QField field) {
        if (dclExecutor.existField(field)) {
            throw new RuntimeException("field names: [" +field.getFieldName()+ "(" + field.getAliasName() + ")] has exists!");
        }
        if (field.getTableName() == null) {
            throw new RuntimeException("field owner table can not be null!");
        }
        field.setDelStatus(0);
        field.setCreateTime(new Date());
        if (field.getSchemeName() == null || field.getSchemeName().isEmpty()) {
            field.setSchemeName(dbRouter.getMaster().getSchemeName());
        }
        if (field.getSourceName() == null || field.getSourceName().isEmpty()) {
            field.setSourceName(dbRouter.getMaster().getSourceName());
        }
        QTable qTable = this.qTableCurd.selectTable(field.getSourceName(), field.getSchemeName(), field.getTableName());
        if (qTable == null) {
            throw new RuntimeException("field owner table is not exists!");
        }
        List<QField> currentField = field.allFields();
        if (currentField != null && !currentField.isEmpty()) {
            for (QField qField : currentField) {
                qField.setTableName(qTable.getTableName());
                qField.setSchemeName(qField.getSchemeName());
                qField.setTableId(qTable.getId());
                QField fieldInserted = this.qFieldCurd.insertFieldInfo(qField);
                if (fieldInserted != null) {
                    this.qCache.setFieldToCache(fieldInserted);
                    if (qField.canBeInTable()) {
                        ddlExecutor.executeCrtField(fieldInserted);
                    }
                }
            }
        }
        return 1;
    }

    public QField getField(String source, String scheme, String tableName, String fieldName) {
        return this.qFieldCurd.selectByTableNameAndFieldName(source, scheme, tableName, fieldName);
    }

    /**
     * 修改字段
     * 注意：修改字段只能修改字段名称。
     * @param field 字段结构
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public int updField(QField field) {
        if (field.getSchemeName() == null || field.getSchemeName().isEmpty()) {
            field.setSchemeName(dbRouter.getMaster().getSchemeName());
        }
        if (field.getSourceName() == null || field.getSourceName().isEmpty()) {
            field.setSourceName(dbRouter.getMaster().getSourceName());
        }
        if (dclExecutor.existField(field)) {
            throw new RuntimeException("field names: [" +field.getFieldName()+ "] has exists!");
        }
        if (field.getTableName() == null) {
            throw new RuntimeException("field owner table can not be null!");
        }
        field.setDelStatus(0);
        QTable qTable = this.qTableCurd.selectTable(field.getSourceName(),field.getSchemeName(), field.getTableName());
        if (qTable == null) {
            throw new RuntimeException("field owner table is not exists!");
        }
        field.setTableId(qTable.getId());

        String fieldType = field.getFieldType();
        FieldTypeCom fieldTypeCom = null;
        if (fieldType != null && !fieldType.isEmpty()) {
            fieldTypeCom = FieldTypeStore.get(fieldType);
            if (!fieldTypeCom.canUpdate()) {
                throw new RuntimeException("field type can not be updated!");
            }
            if (!fieldTypeCom.preUpdate(field)) {
                return 1;
            }
        }
        QField updated = this.qFieldCurd.updateFieldInfo(field);
        if (updated != null) {
            this.qCache.setFieldToCache(updated);
            if (field.canBeInTable()) {
                ddlExecutor.executeUpdField(updated);
            }
        }
        return 1;
    }

    /**
     * 删除字段
     * @param field 字段结构
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public int delField(QField field) {
        String fieldName = field.getFieldName();
        if (fieldName == null || fieldName.isEmpty()) {
            throw new RuntimeException("field name can not be null!");
        }
        String fieldType = field.getFieldType();
        if (fieldType != null && !fieldType.isEmpty()) {
            FieldTypeCom fieldTypeCom = FieldTypeStore.get(fieldType);
            if (fieldTypeCom != null) {
                if (fieldTypeCom.canDelete()) {
                    if (fieldTypeCom.preDelete()) {
                        QField fieldInserted = this.qFieldCurd.deleteFieldInfo(field);
                        if (fieldInserted != null) {
                            this.qCache.delFieldToCache(fieldInserted);
                            ddlExecutor.executeDelField(fieldInserted);
                        }
                    }
                } else {
                    throw new RuntimeException("field type can not be deleted!");
                }
            }
        }
        return 1;
    }
}
